﻿using System;
using System.Text.RegularExpressions;

namespace Storm.TextEditor.Editor.Interacting
{
    /// <summary>
    /// Holds information about a word.
    /// </summary>
    public class WordData
    {
        #region Fields

        private const string VJASS_FUNCTION_PATTERN = @"((?<scope>(private|public))\s+)?(?<constant>constant\s+)?func(tion)?\s(?<interface>interface\s+)?(?<name>[a-zA-Z]\w*)\s+takes\s+(?<arguments>[\w\s,]+)\sreturns\s+(?<return>\w+)";
        private const string VJASS_METHOD_PATTERN = @"((?<scope>(private|public))\s+)?(?<static>static\s+)?(?<constant>constant\s+)?method\s+(?<name>[a-zA-Z]\w*)\s+takes\s+(?<arguments>[\w\s,]+)\sreturns\s+(?<return>\w+)";

        private const string GALAXY_PATTERN = @"";	// Not yet implemented.

        private string name = "";
        private string description = "";
        private string declaration = "";
        private string arguments = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the name of the Word.
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Gets or sets the description of the Word.
        /// </summary>
        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        /// <summary>
        /// Gets or sets the declaration of the Word.
        /// </summary>
        public string Declaration
        {
            get { return declaration; }
            set { declaration = value; }
        }

        /// <summary>
        /// Gets or sets the arguments of the Word.
        /// </summary>
        public string Arguments
        {
            get { return arguments; }
            set { arguments = value; }
        }

        #endregion

        #region Methods

        #region Public

        /// <summary>
        /// "Squishes" a string so we can get the information we want.
        /// </summary>
        /// <remarks>
        /// Instead of setting Name, Declaration and Arguments manually, you can let this method do it for you.
        ///  - Uses Regular Expressions!
        /// </remarks>
        /// <param name="pattern">Language you want to find the match for, eg. vJass or Galaxy.</param>
        /// <param name="findWhat">If pattern is RegexPattern.vJass, you will need to specify whether you want to find a function or a method. For Galaxy, use RegexFind.None.</param>
        /// <param name="text">Text to be searched.</param>
        public void SquishDataFromString(RegexPattern pattern, RegexFind findWhat, string text)
        {
            // Declare our MatchCollection.
            MatchCollection matches = null;

            // Check whether the user wants a vJass or a Galaxy match
            // and set our MatchCollection to check for matches, 
            // following the defined pattern.
            if (pattern == RegexPattern.vJass)
            {
                // The pattern was vJass, we will now check what the
                // user wants us to search for.
                if (findWhat == RegexFind.Function)
                    matches = Regex.Matches(text, VJASS_FUNCTION_PATTERN);
                else if (findWhat == RegexFind.Method)
                    matches = Regex.Matches(text, VJASS_METHOD_PATTERN);
                else if (findWhat == RegexFind.None)
                    // The user specified RegexPattern.vJass and RegexFind.None, tell him/her that he/she can't.
                    throw new ArgumentNullException("findWhat can't be 'RegexFind.None' when pattern is 'RegexPattern.vJass'.");
            }
            else if (pattern == RegexPattern.Galaxy)
                matches = Regex.Matches(text, GALAXY_PATTERN);

            // Check whether we found a match, and if we did, take
            // the first found match and do magik trikz to it.
            if (matches.Count > 0)
            {
                // Squish the data out of the found match.
                name = matches[0].Groups["name"].Value;
                arguments = matches[0].Groups["arguments"].Value;
                declaration = text.Trim(); // Trim the text that the user specified 
                // so we can use it for our declaration.
            }
        }

        /// <summary>
        /// "Squishes" a string so we can get the information we want.
        /// </summary>
        /// <param name="regexPattern">Regular Expression pattern to use for searching the given text.</param>
        /// <param name="text">Text to be searched.</param>
        public void SquishDataFromString(string regexPattern, string text)
        {
            // Declare our MatchCollection with the specified Regular Expression pattern.
            MatchCollection matches = Regex.Matches(text, regexPattern);

            // Check whether we found a match, and if we did, take
            // the first found match and do magik trikz to it.
            if (matches.Count > 0)
            {
                // Squish the data out of the found match.
                name = matches[0].Groups["name"].Value;
                arguments = matches[0].Groups["arguments"].Value;
                declaration = text.Trim(); // Trim the text that the user specified 
                // so we can use it for our declaration.
            }
        }

        #endregion

        #endregion

        /// <summary>
        /// Initializes a new instance of WordData.
        /// </summary>
        public WordData()
        {
        }

        /// <summary>
        /// Initializes a new instance of WordData.
        /// </summary>
        /// <param name="name">Name of the word.</param>
        /// <param name="description">Description of the word.</param>
        /// <param name="declaration">Declaration of the word.</param>
        /// <param name="arguments">Arguments of the word.</param>
        public WordData(string name, string description, string declaration, string arguments)
        {
            this.name = name;
            this.description = description;
            this.declaration = declaration;
            this.arguments = arguments;
        }
    }
}
